package org.hcf.data.redis;

import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.List;

/**
 * Redisson配置
 */
@Configuration
@ConfigurationProperties(prefix = "cluster.redis.servers.config")
@Slf4j
@Data
//@ConditionalOnProperty(name = "server.redisson")
public class RedissonConfig {
    //    @Value("${server.cluster.redis.servers.config.idleConnectionTimeout}")
    int idleConnectionTimeout;
    //    @Value("${server.cluster.redis.servers.config.connectTimeout}")
    int connectTimeout;
    //    @Value("${server.cluster.redis.servers.config.timeout}")
    int timeout;
    //    @Value("${server.cluster.redis.servers.config.retryAttempts}")
    int retryAttempts;
    //    @Value("${server.cluster.redis.servers.config.retryInterval}")
    int retryInterval;
    //    @Value("${server.cluster.redis.servers.config.database}")
    int database;
    //    @Value("${server.cluster.redis.servers.config.username}")
    String username;
    //    @Value("${server.cluster.redis.servers.config.password}")
    String password;
    //    @Value("${server.cluster.redis.servers.config.subscriptionsPerConnection}")
    int subscriptionsPerConnection;
    //    @Value("${server.cluster.redis.servers.config.clientName}")
    String clientName;
    //    @Value("${server.cluster.redis.servers.config.subscriptionConnectionMinimumIdleSize}")
    int subscriptionConnectionMinimumIdleSize;
    //    @Value("${server.cluster.redis.servers.config.subscriptionConnectionPoolSize}")
    int subscriptionConnectionPoolSize;
    //    @Value("${server.cluster.redis.servers.config.readMode}")
    ReadMode readMode;
    //    @Value("${server.cluster.redis.servers.config.nodeAddresses}")
    List<String> nodeAddresses;

    @Bean
    @SuppressWarnings("unchecked")
    public RedissonClient redisson() throws IOException {
        log.info("nodeAddresses:" + JSONObject.toJSONString(nodeAddresses));
        log.info("password:" + password);

//        try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("config/redisson-config.yml")) {
        Config config = new Config();
        config.useSingleServer()
                .setDatabase(database)
                .setUsername(username == null || username.isEmpty() ? null : username)
                .setPassword(password == null || password.isEmpty() ? null : password)
                .setAddress(nodeAddresses.get(0));
        return Redisson.create(config);

//        config.useClusterServers()
//                .setTimeout(timeout)
//                .setClientName(clientName)
//                .setConnectTimeout(connectTimeout)
//                .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize)
//                .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize)
//                .setSubscriptionsPerConnection(subscriptionsPerConnection)
//                .setReadMode(readMode)
//                .setRetryInterval(retryInterval)
//                .setRetryAttempts(retryAttempts)
//                .setIdleConnectionTimeout(idleConnectionTimeout)
//                .setPassword(password == null || password.isEmpty() ? null : password)
//                .setUsername(username == null || username.isEmpty() ? null : username)
//                .setNodeAddresses(nodeAddresses.toList(String.class));

//        }
//        System.err.println("yml参数:nodeAddresses:" + nodeAddresses + ", database:" + database + ", username:" + username + ", password:" + password);
//        try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("config/redisson-config.yml")) {
//            Yaml yml = new Yaml();
//            Map<String, Object> map = yml.load(in);
//            JSONObject redisConfigJson = new JSONObject((Map<String, ?>) map.get("clusterServersConfig"));
//            int database = redisConfigJson.getIntValue("database");
//            String nodeAddresses = redisConfigJson.getJSONArray("nodeAddresses").getString(0);
//            String username = redisConfigJson.getString("username");
//            String password = redisConfigJson.getString("password");
//            System.err.println("配置文件参数:nodeAddresses:" + nodeAddresses + ", database:" + database + ", username:" + username + ", password:" + password);
//            Config config = new Config();
//            config.useSingleServer()
//                    .setDatabase(database)
//                    .setUsername(username)
//                    .setPassword(password)
//                    .setAddress(nodeAddresses);
//            return Redisson.create(config);
//        }

//        try {
//            Config config = Config.fromYAML(Thread.currentThread().getContextClassLoader().getResource("redisson-config.yml"));
//            return Redisson.create(config);
//        } catch (Exception e) {
//            log.error("redisson error!", e);
//            try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("redisson-config.yml")){
//                Yaml yml = new Yaml();
//                Map<String,Object> map = yml.load(in);
//                JSONObject redisConfigJson = new JSONObject((Map<String, ?>) map.get("clusterServersConfig"));
//                int database = redisConfigJson.getIntValue("database");
//                Config config = new Config();
//                config.useSingleServer()
//                        .setDatabase(database)
//                        .setPassword(redisConfigJson.getString("password"))
//                        .setAddress(redisConfigJson.getJSONArray("nodeAddresses").getString(0));
//                return Redisson.create(config);
//            }
//        }
    }

    @SuppressWarnings("unchecked")
    public static <T, V> LocalCachedMapOptions<T, V> defaultCachedMapOptions() {
        return (LocalCachedMapOptions<T, V>) LocalCachedMapOptions.defaults()
                // 用于淘汰清除本地缓存内的元素
                // 共有以下几种选择:
                // LFU - 统计元素的使用频率，淘汰用得最少（最不常用）的。
                // LRU - 按元素使用时间排序比较，淘汰最早（最久远）的。
                // SOFT - 元素用Java的WeakReference来保存，缓存元素通过GC过程清除。
                // WEAK - 元素用Java的SoftReference来保存, 缓存元素通过GC过程清除。
                // NONE - 永不淘汰清除缓存元素。
                .evictionPolicy(LocalCachedMapOptions.EvictionPolicy.NONE)
                // 如果缓存容量值为0表示不限制本地缓存容量大小
                .cacheSize(0)
                // 以下选项适用于断线原因造成了未收到本地缓存更新消息的情况。
                // 断线重连的策略有以下几种：
                // CLEAR - 如果断线一段时间以后则在重新建立连接以后清空本地缓存
                // LOAD - 在服务端保存一份10分钟的作废日志
                //        如果10分钟内重新建立连接，则按照作废日志内的记录清空本地缓存的元素
                //        如果断线时间超过了这个时间，则将清空本地缓存中所有的内容
                // NONE - 默认值。断线重连时不做处理。
                .reconnectionStrategy(LocalCachedMapOptions.ReconnectionStrategy.NONE)
                // 以下选项适用于不同本地缓存之间相互保持同步的情况
                // 缓存同步策略有以下几种：
                // INVALIDATE - 默认值。当本地缓存映射的某条元素发生变动时，同时驱逐所有相同本地缓存映射内的该元素
                // UPDATE - 当本地缓存映射的某条元素发生变动时，同时更新所有相同本地缓存映射内的该元素
                // NONE - 不做任何同步处理
                .syncStrategy(LocalCachedMapOptions.SyncStrategy.INVALIDATE);
        // 每个Map本地缓存里元素的有效时间，默认毫秒为单位
//                .timeToLive(10000)
        // 或者
//                .timeToLive(10, TimeUnit.SECONDS)
        // 每个Map本地缓存里元素的最长闲置时间，默认毫秒为单位
//                .maxIdle(10000)
        // 或者
//                .maxIdle(10, TimeUnit.SECONDS);
    }

}